//
//  TSCMyHttpUtil.m
//  Tsc_IOS
//
//  Created by Rio on 15-8-30.
//  Copyright (c) 2015年 idream. All rights reserved.
//

#import "TSCMyImageUtil.h"
#import "TSCConstants.h"
#import "TSCMyUtil.h"


@implementation TSCMyImageUtil

// 该方法有3个作用：1，缩放图片；2，调整设备拍照后相片旋转的问题；3，调整设备拍照后相片拉长（变窄）的问题
// 作用1参考：http://www.open-open.com/lib/view/open1375933073921.html
// 作用2参考（非最佳答案的simple one解决方案）：http://stackoverflow.com/questions/5427656/ios-uiimagepickercontroller-result-image-orientation-after-upload/5427890
// 作用3参考：TSCVCPhotoEditor.m中，创建_ivPhoto时，使用了这种方法。解释：对于UIImagePickerController通过拍照获得的UIImage，必须使用TSCMyImageUtil->adjustImageOrientation()来进行调整，否则，当设备拍照时为竖屏，则UIImagePickerController返回的UIImage被拉长了（变窄了）！将导致后续的裁剪错误！
+ (UIImage *) scaleImage:(UIImage *)image toSize:(CGSize)size {
    // Create a graphics image context
    UIGraphicsBeginImageContext(size);
    
    // Tell the old image to draw in this new context, with the desired
    // new size
    [image drawInRect:CGRectMake(0,0,size.width,size.height)];
    
    // Get the new image from the context
    UIImage* newImage = UIGraphicsGetImageFromCurrentImageContext();
    
    // End the context
    UIGraphicsEndImageContext();
    
    // Return the new image.
    return newImage;
}

/**
 * 获得图片缩略图。需要配合<ImageView>的scaleType属性一起使用。
 *
 * ZOOM_MODE_ONE_AXIS时，设置scaleType="fitCenter"
 *
 * ZOOM_MODE_FULL_WINDOS时，设置scaleType="center"
 *
 * @author Rio
 * @date 2014-06-07
 *
 * @param filePath
 *            图片路径
 * @param windowWidth
 *            可见视窗宽度，一般是<ImageView>的宽度。
 * @param windowHeight
 *            可见视窗高度，一般是<ImageView>的高度。
 * @param zoomMode
 *            缩放模式
 * @return 如果图片文件不存在，或者无法获得其缩略图（比如图片已经损坏），返回null
 */
+(UIImage *) scaleImage:(UIImage *)image windowW:(CGFloat)windowW windowH:(CGFloat)windowH zoomMode:(NSInteger)zoomMode {
    
    // 获取原图宽高
    CGFloat picW = image.size.width;
    CGFloat picH = image.size.height;
    
    // 缩放因子。值越大，缩小越多；值越小，放大越多
    float scaleFactor = 1.0F;
    
    switch (zoomMode) {
            // 单轴缩放。因为需要缩放的比例选多者，所以取max
        case ZoomModeOneAxis:
            scaleFactor = MAX(picW / windowW, picH / windowH);
            //            scaleFactor = ceil(scaleFactor); // 性能优先时
            //            // scaleFactor = (float) Math.floor(scaleFactor);// 画质优先时
            
            break;
            // 全视窗缩放。因为需要缩放的比例选少者，所以取min
        case ZoomModeFullWindow:
            scaleFactor = MIN(picW / windowW, picH / windowH);
            //            scaleFactor = floor(scaleFactor); // 因为全视窗，只能用floor
            
            break;
        default:
            NSAssert(FALSE, @"[E]%s: 缩放UIImage时，zoomMode的值[%li]不合法！", __FUNCTION__, zoomMode);
    }
    
    // 缩放
    CGSize destSize = CGSizeMake(picW / scaleFactor, picH / scaleFactor);
    return [TSCMyImageUtil scaleImage:image toSize:destSize];
}

/**
 * 调整（通过拍照）获得图片的方向。通过UIImagePickerController拍照获得的图片，其方向（imageOrientation）可能不是正常方向，通过此方法调整为正常方向。否则，将导致裁减图片不正常。
 *
 * @date 2015-09-05
 * @author Rio
 */
+ (UIImage *) adjustImageOrientation:(UIImage *)image {
    // 注：经试验，只有当“Home”按钮在右侧（横屏）拍照时，imageOrientation才是UIImageOrientationUp，其他3种情况，都不是UIImageOrientationUp
    
    if (image.imageOrientation != UIImageOrientationUp) {
        // 以图片原本的尺寸返回
        return [TSCMyImageUtil scaleImage:image toSize:image.size];
    } else {
        // 不用调整，直接返回原图
        return image;
    }
}

+ (MyFileUIImage *) generateThumbnailWithOriginalImage:(UIImage *)originalImage {
    // 先创建一个临时文件，保存原图
    NSString * originalImagePath = [TSCMyUtil makeFile:FileTypeImgTemp fileName:nil overwrite:YES];
    BOOL isSuccess = [UIImageJPEGRepresentation(originalImage, 1.0f) writeToFile:originalImagePath atomically:YES]; // 无损保存
    if (isSuccess == NO) {
        NSLog(@"[W]%s: 创建缩略图时，创建临时文件用于保存原图UIImage时出错！", __FUNCTION__);
    }
    
    // TODO 应该将无损的originalImage传入，而不是间接的通过文件再次生成UIImage，这样很可能导致“有损”！
    return [TSCMyImageUtil generateThumbnailWithOriginalImagePath:originalImagePath];
}

/**
 * 生成某一个图片文件的缩略图，并存放在TEMP文件夹下，同时返回新生成缩略图的File和Bitmap
 * <p>
 *
 * 调用时必须满足：
 * <p>
 * 1. 必须保证在window已获取宽高的情况下调用
 * <p>
 * 2. 必须检查返回是否为null
 * <p>
 *
 * 其他说明：
 * <p>
 * 1. 自动以当前window宽高为目标显示区域
 * <p>
 * 2. 缩略图生成策略同单轴方式
 * <p>
 * 2. 生成的缩略图存放在TEMP文件夹下
 * <p>
 * 3. 生成的缩略图文件名为原图文件名前加“t_”
 * <p>
 * 4. 如果同名文件已经存在，则覆盖（反正在TEMP目录，也无所谓。因为原图有可能被选择两次，
 * 那么第二次缩略图的path就和第一次缩略图的path相同了）
 * <p>
 * 5. 如果缩放比为1，即图片不需要缩放，则不生成缩略图，而把原图file和对原图解码后的Bitmap直接返回
 * <p>
 * 6. 如果第二次选择第一次生成的缩略图作为原图，那么第二次生成的缩略图会比第一次的缩略图略大。估计这是由于jpg压缩时造成的。
 * 起初想针对缩放比为1的图片直接copy，但是由于方法需要返回Bitmap，索性不做这种改动了。
 *
 *
 * @param context
 * @param originalFilePath
 * @return
 */
+ (MyFileUIImage *) generateThumbnailWithOriginalImagePath:(NSString *)originalImagePath {
    
    // 检查文件是否存在。注：如果对不存在的文件进行decodeFile()操作，会爆出“FileNotFoundException”的错误类异常
    NSFileManager * fm = [NSFileManager defaultManager];
    if ([fm fileExistsAtPath:originalImagePath] == NO) {
        NSLog(@"[E]%s: 创建缩略图时，原图文件不存在！", __FUNCTION__);
        return nil;
    }
    
    // 获取原图宽高
    // 注：IOS中，可以直接用UIImage获得大图信息，不必考虑内存问题。因为依据规范，UIImage会自动purge超出内存大小的图片数据
    UIImage * originalImage = [UIImage imageWithContentsOfFile:originalImagePath];
    CGFloat originalW = originalImage.size.width;
    CGFloat originalH = originalImage.size.height;
    
    // 计算缩放比率
    CGFloat reqWidth = UI_SCREEN_WIDTH;
    CGFloat reqHeight = UI_SCREEN_HEIGHT;
    CGFloat scaleFactor = MAX(originalW / reqWidth, originalH / reqHeight); // 缩放策略同单轴，取max
    scaleFactor = ceil(scaleFactor); // 性能优先时
    // scaleFactor = floor(scaleFactor);// 画质优先时
    
    // 根据缩放比例计算新尺寸
    CGSize newSize = CGSizeMake(originalW / scaleFactor, originalH / scaleFactor);
    
    // 缩放
    UIImage * newImage = [TSCMyImageUtil scaleImage:originalImage toSize:newSize];
    if (newImage == nil) {
        NSLog(@"[W]%s: 创建缩略图时，缩小原图出错！可能时原图文件不完整！", __FUNCTION__);
        return nil;
    }
    
    // 旋转
    // TODO
    // TODO
    //    NSInteger angle = getImageFileRotateAngle(originalFile.getAbsolutePath());
    //    bm = rotateBitmap(angle, bm);
    
    // （1）如果不用缩放，直接将原图作为结果返回
    if (scaleFactor == 1.0F) {
        MyFileUIImage * result = [[MyFileUIImage alloc]init];
        result.filePath = originalImagePath;
        result.image = originalImage;
        return result;
    }
    // （2）如果需要缩放
    else {
        // 保存缩略图
        NSString * newImageName = [@"t_" stringByAppendingString:[originalImagePath lastPathComponent]];
        NSString * newImagePath = [TSCMyUtil makeFile:FileTypeImgTemp fileName:newImageName overwrite:YES]; // 注：覆盖
        
        if (newImagePath == nil) {
            NSLog(@"[W]%s: 创建缩略图时，生成缩略图的临时文件失败！", __FUNCTION__);
            return nil;
        }
        
        BOOL isSuccess = [UIImageJPEGRepresentation(newImage, 1.0f) writeToFile:newImagePath atomically:YES]; // 无损写入文件
        if (isSuccess == NO) {
            NSLog(@"[W]%s: 创建缩略图时，写入缩略图失败！", __FUNCTION__);
            return nil;
        }
        
        MyFileUIImage * result = [[MyFileUIImage alloc]init];
        result.filePath = newImagePath;
        result.image = newImage;
        return result;
    }
    
}

/**
 * 根据Android对应的方法，创建适用于IOS的缩略图生成方法。因为在IOS中，使用UIImagePickerController获得UIImage，或者UIImagePickerControllerReferenceURL（也可以转换为ALAsset，再转换为UIImage），而上传图片时，七牛接收的参数是NSData，所以方法的参数为UIImage，返回值为NSData，这样设计比较合理。
 *
 * 注：该方法并不在设备上生成文件，这一点与Android不同！
 *
 * @author Rio
 * @date 2015-09-01
 * @return 如果生成缩略图失败，返回nil
 *
 *
 */
+ (NSData *) getThumbnailWithOriginalImage_1:(UIImage *)originalImage {
    if (originalImage == nil) {
        NSLog(@"[W]%s: 获得缩略图时，参数originalImage为nil！", __FUNCTION__);
        return nil;
    }
    
    // 获取原图宽高
    // 注：IOS中，可以直接用UIImage获得大图信息，不必考虑内存问题。因为依据规范，UIImage会自动purge超出内存大小的图片数据
    CGFloat originalW = originalImage.size.width;
    CGFloat originalH = originalImage.size.height;
    
    // 计算缩放比率
    // TODO 其实这里不应该以当前设备的宽高作为目标尺寸，而应该将所有IOS设备的“平均尺寸”作为目标尺寸
    CGFloat reqWidth = UI_SCREEN_WIDTH;
    CGFloat reqHeight = UI_SCREEN_HEIGHT;
    CGFloat scaleFactor = MAX(originalW / reqWidth, originalH / reqHeight); // 缩放策略同单轴，取max
    scaleFactor = ceil(scaleFactor); // 性能优先时
    // scaleFactor = floor(scaleFactor);// 画质优先时
    
    // 根据缩放比例计算新尺寸
    CGSize newSize = CGSizeMake(originalW / scaleFactor, originalH / scaleFactor);
    
    // （尺寸）缩放
    UIImage * newImage = [TSCMyImageUtil scaleImage:originalImage toSize:newSize];
    if (newImage == nil) {
        NSLog(@"[W]%s: 获得缩略图时，缩小原图出错！可能时原图文件不完整！", __FUNCTION__);
        return nil;
    }
    
    // （大小）缩放
    // 注：缩放比例取0.5f
    return UIImageJPEGRepresentation(newImage, 0.5f);
}

/**
 * 获得某个UIImageView圆形的新UIImageView
 *
 * 参考：http://blog.csdn.net/nogodoss/article/details/28601875
 *
 * @date 2015-09-22
 * @author Rio
 */
+ (UIImage *) getRoundImage:(UIImage *)iv inset:(CGFloat)inset borderWidth:(CGFloat)borderWidth borderColor:(UIColor *)borderColor {
    
    // 注：需检查iv.image不能为nil，否则将爆出如下错误：
    // <Error>: clip: invalid context 0x0. This is a serious error. This application, or a library it uses, is using an invalid context  and is thereby contributing to an overall degradation of system stability and reliability. This notice is a courtesy: please fix this problem. It will become a fatal error in an upcoming update.
    NSAssert(iv, @"[E]%s: 获得圆形UIImage时，传入的UIImage不存在！", __FUNCTION__);
    
    UIGraphicsBeginImageContext(iv.size);
    CGContextRef context = UIGraphicsGetCurrentContext();
    
    // 绘制边框
    if (borderWidth > 0 && borderColor) {
        CGContextSetLineWidth(context, borderWidth);
        CGContextSetStrokeColorWithColor(context, borderColor.CGColor);
    } else {
        // 注：经实际测试发现，如果什么边框都不设置，则系统自动设置宽度为1的黑色边框。为了去掉这个默认边框，加上如下代码：
        CGContextSetLineWidth(context, 0.0f);
    }
    
    CGRect rect = CGRectMake(inset, inset, iv.size.width - inset * 2.0f, iv.size.height - inset * 2.0f);
    CGContextAddEllipseInRect(context, rect);
    CGContextClip(context);
    
    //在圆区域内画出image原图
    [iv drawInRect:rect];
    CGContextAddEllipseInRect(context, rect);
    CGContextStrokePath(context);
    
    //生成新的image
    UIImage *ivNew = UIGraphicsGetImageFromCurrentImageContext();
    
    UIGraphicsEndImageContext();
    
    return ivNew;
}


@end


@implementation MyFileUIImage

@end
